/*
    This source file is part of GeNa project.
    Copyright © GeNa project 2008
    For the latest info, see http://code.google.com/p/genaproject/ or  http://lumpyproject.forums-rpg.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>. */

#include <GL/glew.h>

#ifdef WX_PRECOMP
#ifndef WX_PCH_H_INCLUDED
#include "wx_pch.h"
#endif
#endif
#include <wx/cmdline.h>

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__

#include <boost/filesystem/fstream.hpp>
#include <boost/archive/xml_iarchive.hpp>


#include "application.h"
#include "main_frame.h"

#include "windows_manager.h"
#include "windows_manager_serialization.h"
#include "gl_window.h"
#include "free_camera.h"
#include "property_manager.h"
#include "path.h"
#include "map_manager.h"
#include "unique_name_generator.h"

#include "message.h"

//DEFINE_EVENT_TYPE(wxEVT_CALLFUNCTION)
const wxEventType wxEVT_CALLFUNCTION = wxNewEventType();

IMPLEMENT_APP(Application);


BEGIN_EVENT_TABLE(Application, wxApp)
	EVT_TIMER( ID_RENDERTIMER, Application::onRenderTimer )
	EVT_COMMAND( 0, wxEVT_CALLFUNCTION, Application::onCallFunction)
END_EVENT_TABLE()

Application* Application::sInst = NULL;

Application::Application() : mTimer(this, ID_RENDERTIMER), m_appOut("./triatek.log", std::ios_base::out | std::ios_base::trunc)
{
    sInst = this;
    initOgre = false;
}

extern void fixedTest();

bool Application::OnInit()
{
    wxApp::OnInit();


    //Parse command line
    wxCmdLineParser cmdParser(argc, argv);

    static const wxCmdLineEntryDesc cmdLineDesc[] =
    {
        { wxCMD_LINE_OPTION, _("F"), _("file"), _("la carte qui doit êtrer ouverte") },
        { wxCMD_LINE_SWITCH, _("D"), _("default"), _("Réinitialise la configuration par défaut.") },
        { wxCMD_LINE_NONE }
    };

    cmdParser.SetDesc(cmdLineDesc);
    if(cmdParser.Parse() != 0) //Help printed or command line parsing failure
        return false;

    //Create log
    m_appLog = new wxLogStream(&m_appOut);
    wxLog::SetActiveTarget(m_appLog);


    //Create frame
    m_frame = new MainFrame(0L, _("Éditeur Triatek"));

    wxLogMessage(_("•*´¯`*•.¸ .. Journal de l’Éditeur Triatek .. ¸.•*´¯`*•\n")); //Display first log message
    wxLogMessage(_("Enregistrement des propriétés des objets."));


    //Init GL context
    GLWindow::initGLWindow();


    //Load configuration
    boost::filesystem::ifstream ifs(boost::filesystem::path("./config.xml"));

    if( !ifs.good() || cmdParser.Found(_("D")))
    {
        if( !ifs.good())
            wxLogError(_("Impossible de charger config.xml, la configuration par défaut des options globales sera utilisé."));
        else
            wxLogMessage(_("La configuration par défaut des options globales sera utilisé ( option -D utilisé)."));
        m_frame->SetSize(1000, 600);
        //Nothing else to do
    }
    else
    {
        try
        {
            boost::archive::xml_iarchive ia(ifs);
            try
            {
                ia >> make_nvp("mainFrame",*m_frame);
                ia >> make_nvp("properties",propMgrInstance);
            }
            catch(...)
            {
                std::cout << "Interruption, le fichier config.xml possède des erreurs, veuillez utiliser l’option -D de la ligne de commande pour réinitialiser les paramètres par défaut";
                return false;
            }
        }
        catch(...)
        {
            m_frame->SetSize(1000, 600);
            //Nothing else to do
        }

        ifs.close();
    }

    wxLogMessage(_("Affichage de la fenêtre principale"));
    m_frame->Show();



        appInstance->setupScene();


    m_useDefaultWindowsManager = cmdParser.Found(_("D"));
    if( m_useDefaultWindowsManager)
        wxLogMessage(_("Default configuration asked."));

    mapManagerInstance; //Create the MapManagerInstance
    wxString file;
    Map* map = NULL;
    if( cmdParser.Found(_("F"),&file))
    {
        map = mapManagerInstance.load(std::string(file.mb_str()),boost::filesystem::system_complete(pathListInstance.triatekMapPath));
        wxLogMessage(_("Chargement de %s"), file.c_str());
        if( map)
            wxLogMessage(_("Chargement de %s réussi"), file.c_str());
        else
            wxLogError(_("Échec du chargement de %s"), file.c_str());
    }

    if( map)
        mapManagerInstance.setCurrent(map);
    else
    {
        wxLogMessage(_("Chargement d’une carte vierge"));
        mapManagerInstance.setCurrent(mapManagerInstance.newMap());
    }

    autosaveInterval = 100*60*1;
    autosaveTime = 0;
    glewInitialized = false;
    mTimer.Start(10);
    return true;
}




void Application::setupScene()
{
//    mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC,"Level");
//
//    Ogre::Entity *ent0 = mSceneMgr->createEntity( "Axis", "axis.mesh" );
//    for( int i=0; i< ent0->getMesh()->getNumSubMeshes(); i++)
//        ent0->getMesh()->getSubMesh(i)->setMaterialName("gridwnd/default");
//    Ogre::SceneNode *node0 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Axis", Ogre::Vector3( 0, 0, 0 ) );
//    node0->attachObject( ent0 );

//    Ogre::Entity *ent1 = mSceneMgr->createEntity( "Terminal", "Plane.134.mesh" );
//    Ogre::SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Terminal", Ogre::Vector3( 0, 50, 0 ) );
//    node1->attachObject( ent1 );
//
//    Ogre::Entity *ent2 = mSceneMgr->createEntity( "Suzanne", "Suzanne.mesh" );
//    Ogre::SceneNode *node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Suzanne", Ogre::Vector3( -10, 0, 0 ) );
//    node2->attachObject( ent2 );
//
//    Ogre::Entity *ent3 = mSceneMgr->createEntity( "Terminal2", "Plane.134.mesh" );
//    Ogre::SceneNode *node3 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Terminal2", Ogre::Vector3( 0, -50, 0 ) );
//    node3->attachObject( ent3 );
//
//    Ogre::Entity *ent4 = mSceneMgr->createEntity( "Terminal3", "Plane.134.mesh" );
//    Ogre::SceneNode *node4 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Terminal3", Ogre::Vector3( 50, 0, 0 ) );
//    node4->attachObject( ent4 );

}

int glGetInteger(GLenum integer)
{
    int a;
    glGetIntegerv(integer, &a);
    return a;
}

void Application::onRenderTimer(wxTimerEvent &event)
{
    while(!glewInitialized)
    {
        GLenum err = glewInit();

        if( err == 1)
            return;

        wxLogMessage(_("Using GLEW %s"), wxString((const char*)glewGetString(GLEW_VERSION),wxConvUTF8).c_str());
        if (GLEW_OK != err)
        {
            /* Problem: glewInit failed, something is seriously wrong. */
            wxLogMessage(_("GLEW Error : %s"), wxString((const char*)glewGetErrorString(err),wxConvUTF8).c_str());
        }
        else
        {
            wxLogMessage(_("Using OpenGl %s"),wxString((const char*)glGetString(GL_VERSION) ,wxConvUTF8).c_str());
            wxLogMessage(_("%s %s"), wxString((const char*)glGetString(GL_RENDERER) ,wxConvUTF8).c_str(), wxString((const char*)glGetString(GL_VENDOR) ,wxConvUTF8).c_str());
            wxLogMessage(_("Extensions list : %s"),wxString((const char*)glGetString(GL_EXTENSIONS) ,wxConvUTF8).c_str());
        }

        if(GLEW_ARB_vertex_buffer_object)
            wxLogMessage(_("Vertex Buffer Object supported"));
        else
            wxLogMessage(_("Vertex Buffer Object unsupported"));

        wxLogMessage(_("Context information :\nColor Buffer Bits : R%dG%dB%dA%d Depth Buffer Bits : %d Stencil Buffer Bits : %d"), glGetInteger(GL_RED_BITS), glGetInteger(GL_RED_BITS), glGetInteger(GL_GREEN_BITS), glGetInteger(GL_BLUE_BITS), glGetInteger(GL_ALPHA_BITS), glGetInteger(GL_DEPTH_BITS), glGetInteger(GL_STENCIL_BITS));
        wxLogMessage(_("Max Texture Units : %d Max texture size : %d 3d Max texture size : %d"), glGetInteger(GL_MAX_TEXTURE_UNITS), glGetInteger(GL_MAX_TEXTURE_SIZE), glGetInteger(GL_MAX_3D_TEXTURE_SIZE));

        glewInitialized = true;

    }


    if( autosaveTime < autosaveInterval)
        autosaveTime += event.GetInterval();
    else
    {
        autosaveTime = 0;
        mapManagerInstance.autoSave();
    }

    GLWindow::processRenderTimer(event.GetInterval());
}

